/* --- 使用Set --- 


我们知道，Map用于存储key-value的映射，对于充当key的对象，是不能重复的，并且，不但需要正确覆写equals()方法，还要正确覆写hashCode()方法。


如果我们只需要存储不重复的key，并不需要存储映射的value，那么就可以使用Set。


'Set' 用于存储不重复的元素集合，它主要提供以下几个方法：

	· 将元素添加进Set<E>：boolean add(E e)
	· 将元素从Set<E>删除：boolean remove(Object e)
	· 判断是否包含元素：boolean contains(Object e)


我们来看几个简单的例子：	*/
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Set<String> set = new HashSet<>();

		System.out.println(set.add("abc")); //true
		System.out.println(set.add("xyz")); //true
		System.out.println(set.add("xyz")); //false,重复了

		System.out.println(set.contains("xyz")); //true
		System.out.println(set.contains("XYZ")); //false

		System.out.println(set.remove("hello")); //false,元素不存在

		System.out.println(set.size()); // 2
	}
}

/*
Set实际上相当于只存储key、不存储value的Map。我们经常用Set用于去除重复元素。

因为放入Set的元素和Map的key类似，都要正确实现equals()和hashCode()方法，否则该元素无法正确地放入Set。

最常用的Set实现类是HashSet，实际上，HashSet仅仅是对HashMap的一个简单封装，（对...封装:在某个class的功能之上进行屏蔽/添加,实现出新的功能对象) 

HashSet对HashMap的封装：将HashMap的value功能屏蔽,得到HashSet

它的核心代码如下：	*/
public class HashSet<E> implements Set<E> {
	//持有一个HashMap：
	private HashMap<E, Object> map = new HashMap<>();

	//放入HashMap的value:
	private static final Object PRESENT = new Object();

	public boolean add(E e) {
		return map.put(e, PRESENT) == null; 
		//put的返回值,若无value则返回null
		// null == null ? 1 : 0
	}

	public boolean contains(Object o) {
		return map.containsKey(o);
	}

	public boolean remove(Object o) {
		return map.remove(o) == PRESENT;
	}
}

/*
Set接口并不保证有序，而SortedSet接口则保证元素是有序的：

HashSet是无序的，因为它实现了Set接口，并没有实现SortedSet接口；
TreeSet是有序的，因为它实现了SortedSet接口。
用一张图表示：

	       ┌───┐
	       │Set│
	       └───┘
	         ▲
	    ┌────┴─────┐
	    │          │
	┌───────┐ ┌─────────┐
	│HashSet│ │SortedSet│
	└───────┘ └─────────┘
	               ▲
	               │
	          ┌─────────┐
	          │ TreeSet │
	          └─────────┘


我们来看HashSet的输出：	*/
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Set<String> set = new HashSet<>();

		set.add("apple");
		set.add("banana");
		set.add("pear");
		set.add("orange");

		for (String s : set) {
			System.out.println(s);
		}
	}
}


/*
注意输出的顺序既不是添加的顺序，也不是String排序的顺序，在不同版本的JDK中，这个顺序也可能是不同的。


--------------------------------


把HashSet换成TreeSet，在遍历TreeSet时，输出就是有序的，这个顺序是元素的排序顺序：	*/
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Set<String> set = new TreeSet<>();

		set.add("apple");
		set.add("banana");
		set.add("pear");
		set.add("orange");

		for (String s : set) {
			System.out.println(s);
		}
	}
}

/*
使用TreeSet和使用TreeMap的要求一样，添加的元素必须正确实现Comparable接口，如果没有实现Comparable接口，那么创建TreeSet时必须传入一个Comparator对象。
*/


/*  # 练习

在聊天软件中，发送方发送消息时，遇到网络超时后就会自动重发，因此，接收方可能会收到重复的消息，在显示给用户看的时候，需要首先去重。请练习使用Set去除重复的消息：	*/
import java.util.*;

public class Main {
	public static void main(String[] args) {
		List<Message> received = List.of(
			new Message(1, "Hello!"),
			new Message(2, "发工资了吗"),
			new Message(2, "发工资了吗"),
			new Message(3, "去哪里吃饭"),
			new Message(3, "去哪里吃饭"),
			new Message(4, "Bye")	
		);

		List<Message> displayMessages = process(received);

		for (Message message : displayMessages) {
			System.out.println(message.text);
		}
	}

	static List<Message> process(List<Message> received) {
		// TODO:按sequence去除重复消息

		//方法1：在class Message中@Override compareTo方法
		Set<Message> message_Set = new TreeSet<Message>();
		message_Set.addAll(received); 
			//Set<>().addAll(List)会自动排除同样的

		//方法2：在new TreeSet<Message(new Comparator{...});中@Override
		Set<Message> message_Set = new TreeSet<Message>(new Comparator<Message>() {
			@Override
			public int compare(Message m1, Message m2) {
				return Integer.compare(m1.sequence, m2.sequence);
			}
		})

	//方法1、2都需要用到
		List<Message> message_list = new ArrayList<Message>();
		message_list.addAll(message_Set);

		return message_list;
	}
}

class Message {
	public final int sequence;
	public final String text;

	public Message(int sequence, String text) {
		this.sequence = sequence;
		this.text = text;
	}

	//方法1
	@Override
	public int compareTo(Message o) {
		return Integer.compare(this.sequence, o.sequence);
	}
}






/* --- 使用Set の 小结 --- 


1. Set用于存储不重复的元素集合：
	· 放入HashSet的元素与作为HashMap的key要求相同；
	· 放入TreeSet的元素与作为TreeMap的Key要求相同；

2. 利用Set可以去除重复元素；

3. 遍历SortedSet按照元素的排序顺序遍历，也可以自定义排序算法。



*/



































